﻿// Shader-Based-Image-Processing (SBIP)
// http://code.google.com/p/sbip/
//
// Copyright © Frank Nagl, 2009-2011
// admin@franknagl.de
//
namespace SBIP.Filter.NonSBIP
{
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Windows.Forms;
    using Helper;
    using SBIP.Controls;
    using SBIP.Helper.ColorSpace;
    using cp = SBIP.Helper.ColorPalette;

    public class NSSimpleLuvColorSegmentation : BaseNonSBIPFilter
    {       
        #region properties

        /// <summary> Determiens, whether the progress is shown in a window.
        /// </summary>
        public bool ShowProgressBar { get; set; }

        /// <summary> Segmentation tolerance for allowed euclidian distance of 
        /// similar LUV colors. Default: 2.5.</summary>
        /// 
        /// 
        public float ColorDistance { get; set; }

        #endregion properties

        /// <summary>
        /// Initializes a new instance of the 
        /// <see cref="NSSimpleLuvColorSegmentation"/> class.
        /// </summary>
        public NSSimpleLuvColorSegmentation()
        {
            SupportedSrcPixelFormats = PixelFormatFlags.Color;
            ColorDistance = 2.5f;
            ShowProgressBar = true;
        }

        /// <summary>
        /// Processes the image.
        /// </summary>
        /// <param name="srcData">The source bitmap data.</param>
        /// <param name="dstData">The destination bitmap data.</param>
        protected override void Process(BitmapData srcData, BitmapData dstData)
        {
            int w = srcData.Width;
            int h = srcData.Height;
            int pixelSize = Image.GetPixelFormatSize(srcData.PixelFormat) / 8;
            //All Colors with their id for the colorTable
            Dictionary<Color, int> colors = new Dictionary<Color, int>();
            int offset = srcData.Stride - w * pixelSize;
            int colorId = 0;         

            // segment the image
            unsafe
            {
                byte* src = (byte*)srcData.Scan0.ToPointer();
                byte* dst = (byte*)dstData.Scan0.ToPointer();
                ProgressBarForm form = null;
                if (ShowProgressBar)
                {                    
                    form = 
                        new ProgressBarForm
                        {
                            ProgressBar = { Maximum = h },
                            StartPosition = FormStartPosition.CenterScreen
                        };
                    form.Show();
                    // form.TopMost = true;                    
                }

                // for each line
                for (int y = 0; y < h; y++)
                {
                    if (ShowProgressBar && form != null)
                    {
                        // do something ...
                        form.Text = @"Progress: " + (int)((float)y / h * 100) + @"%";
                        form.Resultlabel.Text = @"Lines to process: " + (h - 1- y);
                        form.ProgressBar.PerformStep();
                        form.Refresh();                        
                    }
                    // for each pixel in line
                    for (int x = 0; x < w; x++, src += pixelSize, dst += pixelSize)
                    {
                        Color col = Color.FromArgb(
                            src[RGBA.R], src[RGBA.G], src[RGBA.B]);
                        RGB rgb1 = new RGB(src[RGBA.R], src[RGBA.G], src[RGBA.B]);
                        LUV luv1 = rgb1.To<LUV>();

                        int tempId = -1;
                        foreach (KeyValuePair<Color, int> pair in colors)
                        {
                            RGB rgb2 = new RGB(pair.Key.R, pair.Key.G, pair.Key.B);
                            LUV luv2 = rgb2.To<LUV>();

                            float e = luv1.Color.ColorDistance(luv2.Color);
                            //// only u and v channel
                            //float e = Vector.Distance(
                            //    luv1.Color.B, luv1.Color.C, luv2.Color.B, luv2.Color.C);
                            if (e < ColorDistance)
                            {
                                //colors.TryGetValue(col, out tempId);
                                tempId = pair.Value;
                                break;
                            }
                        }

                        //if (colors.ContainsKey(col))
                        //{
                        //    colors.TryGetValue(col, out tempId);
                        //}
                        if (tempId == -1)
                        {
                            colorId++;
                            if (colorId == cp.ColorCount)
                            {
                                colorId = 0;
                            }
                            tempId = colorId;
                            colors.Add(col, tempId);
                        }

                        dst[RGBA.R] = cp.Colors[tempId].R;
                        dst[RGBA.G] = cp.Colors[tempId].G;
                        dst[RGBA.B] = cp.Colors[tempId].B;
                        if (pixelSize == 4)
                        {
                            dst[RGBA.A] = src[RGBA.A];
                        }
                    }
                    src += offset;
                    dst += offset;
                }

                if (ShowProgressBar && form != null)
                {
                    form.Dispose();
                    MessageBox.Show(colors.Count + @" Segments.");
                }
            }
        }
    }
}
